home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 11 / Cream of the Crop 11-2.iso / os2 / gnucal.zip / gcal_tty.c < prev    next >
C/C++ Source or Header  |  1995-12-01  |  56KB  |  1,884 lines

  1. /*
  2. *  gcal_tty.c:  Manages the tty detection and I/O handling
  3. *
  4. *
  5. *  Copyright (C) 1994, 1995 Thomas Esken
  6. *
  7. *  This software doesn't claim completeness, correctness or usability.
  8. *  On principle I will not be liable for any damages or losses (implicit
  9. *  or explicit), which result from using or handling my software.
  10. *  If you use this software, you agree without any exception to this
  11. *  agreement, which binds you LEGALLY !!
  12. *
  13. *  This program is free software; you can redistribute it and/or modify
  14. *  it under the terms of the `GNU General Public License' as published by
  15. *  the `Free Software Foundation'; either version 2, or (at your option)
  16. *  any later version.
  17. *
  18. *  You should have received a copy of the `GNU General Public License'
  19. *  along with this program; if not, write to the:
  20. *    Free Software Foundation
  21. *    59 Temple Place, Suite 330
  22. *    Boston, MA 02111-1307  USA
  23. */
  24.  
  25.  
  26.  
  27. #ifdef RCSID
  28. static char rcsid[]="$Id: gcal_tty.c 0.38 1995/12/01 00:03:08 tom Exp $";
  29. #endif
  30.  
  31.  
  32.  
  33. /*
  34. *  Include header files
  35. */
  36. #include "gcal_tai.h"
  37. #if HAVE_CTYPE_H
  38. #  include <ctype.h>
  39. #endif
  40. #if HAVE_SYS_TYPES_H
  41. #  include <sys/types.h>
  42. #endif
  43. #if USE_PAGER || USE_HLS
  44. #  if defined(UNIX) && !defined(DJG)
  45. #    if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS
  46. #      include <termios.h>
  47. #      if HAVE_SYS_IOCTL_H && !defined(TIOCGWINSZ)
  48. #        include <sys/ioctl.h>
  49. #      endif
  50. #    else /* !HAVE_TERMIOS_H || !HAVE_TERMIOS_FUNCS */
  51. #      if HAVE_TERMIO_H
  52. #        include <termio.h>
  53. #      else /* !HAVE_TERMIO_H */
  54. #        include <sgtty.h>
  55. #        if HAVE_SYS_IOCTL_H && (defined(WIOCGETD) || defined(TIOCGWINSZ) || defined(TCGETA) || defined(TIOCGETP))
  56. #          include <sys/ioctl.h>
  57. #        endif
  58. #      endif /* !HAVE_TERMIO_H */
  59. #    endif /* !HAVE_TERMIOS_H || !HAVE_TERMIOS_FUNCS */
  60. /*
  61. *  For the Unix PC (ATT 7300 & 3B1):  (taken from less-278 by Mark Nudelman)
  62. *  Since WIOCGETD is defined in sys/window.h, we can't use that to decide
  63. *  whether to include sys/window.h.  Use SIGPHONE from sys/signal.h instead.
  64. */
  65. #    ifndef TIOCGWINSZ
  66. #      include <sys/signal.h>
  67. #      ifdef SIGPHONE
  68. #        include <sys/window.h>
  69. #      endif
  70. #    endif
  71. #    if HAVE_SYS_STREAM_H
  72. #      include <sys/stream.h>
  73. #    endif
  74. #    if HAVE_SYS_PTEM_H
  75. #      include <sys/ptem.h>
  76. #    endif
  77. #  endif /* UNIX && !DJG */
  78. #  ifdef DJG
  79. #    include <pc.h>
  80. #  else /* !DJG */
  81. #    if defined(UNIX) || (defined(OS2) && defined(__GNUC__))
  82. #      if HAVE_TERMCAP_H && (HAVE_LIBTERMCAP || HAVE_LIBTERMLIB)
  83. #        if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS && defined(OS2) && defined(__GNUC__)
  84. #          include <termios.h>
  85. #        endif
  86. #        include <termcap.h>
  87. #      else /* !HAVE_TERMCAP_H || (!HAVE_LIBTERMCAP && !HAVE_LIBTERMLIB) */
  88. #        if HAVE_LIBTERMCAP || HAVE_LIBTERMLIB
  89. IMPORT int   tgetent __P_((char *buffer, char *termtype));
  90. IMPORT int   tgetnum __P_((char *name));
  91. #          if USE_HLS
  92. IMPORT char *tgetstr __P_((char *name, char **area));
  93. IMPORT char *tputs __P_((char *string, int nlines, int (*outfunc)()));
  94. #          endif
  95. #          if USE_PAGER
  96. IMPORT int   tgetflag __P_((char *name));
  97. #          endif /* USE_PAGER */
  98. #        endif /* HAVE_LIBTERMCAP || HAVE_LIBTERMLIB */
  99. #      endif /* !HAVE_TERMCAP_H || (!HAVE_LIBTERMCAP && !HAVE_LIBTERMLIB) */
  100. #      if MUST_DCL_OSPEED && USE_HLS
  101. IMPORT short ospeed;   /* Terminal output baud rate */
  102. /*
  103.    On Solaris2, sys/types.h #includes sys/reg.h, which #defines PC.
  104.    Unfortunately, PC is a global variable used by the Termcap library.
  105. */
  106. #        ifdef PC
  107. #          undef PC
  108. #        endif
  109. IMPORT char  PC;       /* Padding character */
  110. #      endif /* MUST_DCL_OSPEED && USE_HLS */
  111. #    endif /* UNIX || (OS2 && __GNUC__) */
  112. #  endif /* !DJG */
  113. #endif /* USE_PAGER || USE_HLS */
  114. #include "gcal.h"
  115.  
  116.  
  117.  
  118. /*
  119. *  Function prototypes
  120. */
  121. #if __cplusplus
  122. export "C"
  123. {
  124. #endif
  125. /*
  126. ************************************************** Defined in `gcal_utl.c'
  127. */
  128. IMPORT VOID_PTR
  129. my_malloc __P_((const int   amount,
  130.                 const int   exit_status,
  131.                 const char *module_name,
  132.                 const int   module_line,
  133.                 const char *var_name,
  134.                 const int   var_contents));
  135. IMPORT void
  136. my_error __P_((const int   exit_status,
  137.                const char *module_name,
  138.                const int   module_line,
  139.                const char *var_name,
  140.                const int   var_contents));
  141. IMPORT int
  142. my_atoi __P_((const char *s));
  143. /*
  144. ************************************************** Defined in `gcal_tty.c'
  145. */
  146. EXPORT void
  147. print_text __P_((      FILE       *fp,
  148.                        char       *txt_line,
  149.                  const Dmode_enum  mode));
  150. EXPORT void
  151. get_tty_hls __P_((const char *sequence_str));
  152. #if USE_PAGER
  153. EXPORT void
  154. get_tty_scr_size __P_((int *rows,
  155.                        int *cols));
  156. #endif
  157. #if USE_HLS || USE_PAGER
  158. #  ifdef GCAL_TCAP
  159. LOCAL Bool
  160. open_termcap __P_((void));
  161. #    if USE_HLS
  162. LOCAL void
  163. get_ospeed __P_((void));
  164. LOCAL int
  165. outchar __P_((int ch));
  166. LOCAL Bool
  167. get_termcap_hls __P_((Bool *hls1_set,
  168.                       Bool *hls2_set));
  169. #    endif /* USE_HLS */
  170. #    if USE_PAGER
  171. LOCAL Bool
  172. get_termcap_scr_attrib __P_((int *rows,
  173.                              int *cols));
  174. #    endif /* USE_PAGER */
  175. #  else /* !GCAL_TCAP */
  176. #    if defined(MSDOS) && USE_PAGER
  177. LOCAL Uchar
  178. peek_byte __P_((Uint segment,
  179.                 Uint offset));
  180. #    endif
  181. #  endif /* GCAL_TCAP */
  182. #endif /* USE_HLS || USE_PAGER */
  183. LOCAL void
  184. get_hl_seq __P_((const char *sequence_str,
  185.                        Bool *hls1_set,
  186.                        Bool *hls2_set));
  187. #if !HAVE_STRTOL
  188. LOCAL int
  189. sbyte2int __P_((const char *s,
  190.                 const int   base));
  191. #endif
  192. #if !HAVE_STRSTR
  193. LOCAL char *
  194. my_strstr __P_((const char *txt,
  195.                 const char *pat));
  196. #endif /* !HAVE_STRSTR */
  197. #if __cplusplus
  198. }
  199. #endif
  200.  
  201.  
  202.  
  203. /*
  204. *  Declare public(extern) variables
  205. */
  206. #ifdef GCAL_EMAIL
  207. IMPORT FILE       *tfp;                       /* Temporary file, which is send by mailer */
  208. #endif
  209. IMPORT Hls_struct  ehls1s;                    /* Effective hls 1 start (current day) */
  210. IMPORT Hls_struct  ehls1e;                    /* Effective hls 1 end (current day) */
  211. IMPORT Hls_struct  ehls2s;                    /* Effective hls 2 start (holiday) */
  212. IMPORT Hls_struct  ehls2e;                    /* Effective hls 2 end (holiday) */
  213. IMPORT int         warning_level;             /* --debug[=0...WARN_LVL_MAX] */
  214. IMPORT int         is_tty;                    /* Is output displayed on a terminal? */
  215. IMPORT int         is_tty1;                   /* Is output directed to channel 1? */
  216. IMPORT int         is_tty2;                   /* Is output directed to channel 2? */
  217. IMPORT int         tty_rows;                  /* Number of tty rows */
  218. IMPORT int         tty_cols;                  /* Number of tty columns */
  219. IMPORT char        s[MAXLEN+1];               /* General purpose text buffer */
  220. #ifdef GCAL_EPAGER
  221. IMPORT char       *ext_pager;                 /* Name of external pager program */
  222. #endif
  223. IMPORT Bool        emu_hls;                   /* Must we emulate the highlighting sequences? */
  224. IMPORT Bool        suppr_cal_flag;            /* -u */
  225. IMPORT Bool        highlight_flag;            /* -H<yes> or -H<no> */
  226. #if USE_PAGER
  227. IMPORT Bool        pager_flag;                /* -p */
  228. #endif
  229.  
  230.  
  231.  
  232. /*
  233.    Define local(static) variables
  234. */
  235. #if USE_PAGER || USE_HLS
  236. #  ifdef GCAL_TCAP
  237. #    if USE_HLS
  238. LOCAL FILE  *fp_outchar;         /* File which tputs() uses */
  239. #    endif
  240. LOCAL char   tc_buf[4096];       /* Module global Termcap buffer */
  241. LOCAL Bool   tc_no_error=TRUE;   /* Termcap access error occurred */
  242. #    if MUST_DCL_OSPEED && USE_HLS
  243. extern short ospeed;             /* Terminal output baud rate */
  244. extern char  PC;                 /* Padding character */
  245. #    endif
  246. #  endif /* GCAL_TCAP */
  247. #  if USE_PAGER
  248. LOCAL Bool   tty_am=TRUE;        /* Terminal has automatic margins */
  249. LOCAL Bool   tty_xn=FALSE;       /* Terminal ignores newline after wrap */
  250. #  endif /* USE_PAGER */
  251. #endif /* USE_PAGER || USE_HLS */
  252.  
  253.  
  254.  
  255. #ifdef ANSI_PROTO
  256. PUBLIC void
  257. print_text (      FILE       *fp,
  258.                   char       *txt_line,
  259.             const Dmode_enum  mode)
  260. #else /* !ANSI_PROTO */
  261.    PUBLIC void
  262. print_text (fp, txt_line, mode)
  263.          FILE       *fp;
  264.          char       *txt_line;
  265.    const Dmode_enum  mode;
  266. #endif /* !ANSI_PROTO */
  267. /*
  268.    This is the central tty output function, which works according to
  269.      actual display mode and suppress flag.  It prints a line of text
  270.      given in `txt_line' with newline to file `fp' with paging option
  271.      (very poor and simple paging, only used if preprocessor symbol USE_PAGER
  272.      is defined) and deletes ALWAYS delivered `txt_line' automatically
  273.      after printing (*txt_line = '\0').
  274. */
  275. {
  276.    if (   !suppr_cal_flag
  277.        || (   suppr_cal_flag
  278.            && (mode != CAlendar)))
  279.     {
  280. #if USE_PAGER || (defined(GCAL_TCAP) && USE_HLS)
  281.       if (   is_tty
  282.           && is_tty1
  283.           && is_tty2
  284. #  ifdef GCAL_EPAGER
  285.           && (ext_pager == (char *)NULL)
  286. #  endif
  287.          )
  288.        {
  289.          register int    hls_pos=-1;
  290.          register int    hls1_pos=-1;
  291.          register int    hls2_pos=-1;
  292.          register int    nl;
  293.          register int    j;
  294. #  if USE_PAGER
  295.          register int    k;
  296.          static   int    lines_printed=0;
  297. #  endif
  298.          auto     int    i=0;
  299.          auto     int    hls_chars=0;
  300.          auto     char  *ptr_1hls=(char *)NULL;
  301.          auto     char  *ptr_2hls=(char *)NULL;
  302.          auto     Bool   hls_start;
  303. #  if USE_PAGER
  304.          auto     Bool   print_hls=(Bool)(is_tty&&highlight_flag&&!emu_hls);
  305. #  endif
  306.          auto     Bool   nl_found=FALSE;
  307.  
  308.  
  309. #  if defined(GCAL_TCAP) && USE_HLS
  310.          fp_outchar = fp;
  311. #  endif
  312.          LOOP
  313.           {
  314.             j = 0;
  315.             nl = 0;
  316.             if (   highlight_flag
  317.                 && !emu_hls)
  318.              {
  319.                /*
  320.                   Try to detect a highlighting sequence,
  321.                     store its position and point to it...
  322.                */
  323.                hls_pos=hls1_pos=hls2_pos = -1;
  324.                if (*(txt_line + i))
  325.                 {
  326.                   ptr_1hls = strstr(txt_line+i, ehls1s.seq);
  327.                   if (ptr_1hls != (char *)NULL)
  328.                     hls1_pos = (int)strlen(txt_line+i) - strlen(ptr_1hls);
  329.                   ptr_2hls = strstr(txt_line+i, ehls2s.seq);
  330.                   if (ptr_2hls != (char *)NULL)
  331.                     hls2_pos = (int)strlen(txt_line+i) - strlen(ptr_2hls);
  332.                   if (   (ptr_1hls != (char *)NULL)
  333.                       && (ptr_2hls != (char *)NULL))
  334.                    {
  335.                      if (hls1_pos > hls2_pos)
  336.                        hls_pos = hls2_pos;
  337.                      else
  338.                        hls_pos = hls1_pos;
  339.                    }
  340.                   else
  341.                     if (ptr_1hls != (char *)NULL)
  342.                       hls_pos = hls1_pos;
  343.                     else
  344.                       if (ptr_2hls != (char *)NULL)
  345.                         hls_pos = hls2_pos;
  346.                 }
  347.              }
  348.             /*
  349.                No `\n'-NEWLINE character and no real highlighting sequence found:
  350.                  print whole line
  351.             */
  352.             if (   (strchr(txt_line, '\n') == (char *)NULL)
  353.                 && (ptr_1hls == (char *)NULL)
  354.                 && (ptr_2hls == (char *)NULL)
  355.                )
  356.              {
  357.                i = (int)strlen(txt_line);
  358.                fprintf(fp, "%s\n", txt_line);
  359.              }
  360.             else
  361.              {
  362.                hls_start = TRUE;
  363.                while (*(txt_line + i))
  364.                 {
  365.                   /*
  366.                      `\n'-NEWLINE character found (actual line must be a RC
  367.                      fixed date => TILDE-character expansion was performed):
  368.                        print this newline
  369.                   */
  370.                   if (*(txt_line + i) == '\n')
  371.                    {
  372.                      i++;
  373.                      if (j)
  374.                        nl++;
  375.                      nl_found = TRUE;
  376.                      break;
  377.                    }
  378.                   /*
  379.                      Look for a real highlighting sequence;
  380.                        if found, store its length in `hls_chars'
  381.                        and print it explicitly
  382.                   */
  383.                   if (   highlight_flag
  384.                       && !emu_hls
  385.                       && (i == hls_pos))
  386.                    {
  387.                      if (hls_pos == hls1_pos)
  388.                       {
  389.                         if (hls_start)
  390.                          {
  391. #  if defined(GCAL_TCAP) && USE_HLS
  392.                            tputs((char *)ehls1s.seq, 1, outchar);
  393. #  else /* !GCAL_TCAP || !USE_HLS */
  394.                            fputs(ehls1s.seq, fp);
  395. #  endif /* !GCAL_TCAP || !USE_HLS */
  396.                            hls_chars += ehls1s.len;
  397.                            i += ehls1s.len;
  398.                            ptr_1hls = strstr(txt_line+i, ehls1e.seq);
  399.                            if (ptr_1hls != (char *)NULL)
  400.                              hls_pos=hls1_pos = (int)(strlen(txt_line+i) - strlen(ptr_1hls)) + i;
  401.                            else
  402.                              hls_pos = hls2_pos;
  403.                            hls_start = FALSE;
  404.                          }
  405.                         else
  406.                          {
  407. #  if defined(GCAL_TCAP) && USE_HLS
  408.                            tputs((char *)ehls1e.seq, 1, outchar);
  409. #  else /* !GCAL_TCAP || !USE_HLS */
  410.                            fputs(ehls1e.seq, fp);
  411. #  endif /* !GCAL_TCAP || !USE_HLS */
  412.                            hls_chars += ehls1e.len;
  413.                            i += ehls1e.len;
  414.                            ptr_1hls = strstr(txt_line+i, ehls1s.seq);
  415.                            if (ptr_1hls != (char *)NULL)
  416.                              hls_pos=hls1_pos = (int)(strlen(txt_line+i) - strlen(ptr_1hls)) + i;
  417.                            else
  418.                              hls_pos = hls2_pos;
  419.                            hls_start = TRUE;
  420.                          }
  421.                         if (*(txt_line + i))
  422.                           fputc(*(txt_line+i), fp);
  423.                         else
  424.                           break;
  425.                       }
  426.                      else
  427.                        if (hls_pos == hls2_pos)
  428.                         {
  429.                           if (hls_start)
  430.                            {
  431. #  if defined(GCAL_TCAP) && USE_HLS
  432.                              tputs((char *)ehls2s.seq, 1, outchar);
  433. #  else /* !GCAL_TCAP || !USE_HLS */
  434.                              fputs(ehls2s.seq, fp);
  435. #  endif /* !GCAL_TCAP || !USE_HLS */
  436.                              hls_chars += ehls2s.len;
  437.                              i += ehls2s.len;
  438.                              ptr_2hls = strstr(txt_line+i, ehls2e.seq);
  439.                              if (ptr_2hls != (char *)NULL)
  440.                                hls_pos=hls2_pos = (int)(strlen(txt_line+i) - strlen(ptr_2hls)) + i;
  441.                              else
  442.                                hls_pos = hls1_pos;
  443.                              hls_start = FALSE;
  444.                            }
  445.                           else
  446.                            {
  447. #  if defined(GCAL_TCAP) && USE_HLS
  448.                              tputs((char *)ehls2e.seq, 1, outchar);
  449. #  else /* !GCAL_TCAP || !USE_HLS */
  450.                              fputs(ehls2e.seq, fp);
  451. #  endif /* !GCAL_TCAP || !USE_HLS */
  452.                              hls_chars += ehls2e.len;
  453.                              i += ehls2e.len;
  454.                              ptr_2hls = strstr(txt_line+i, ehls2s.seq);
  455.                              if (ptr_2hls != (char *)NULL)
  456.                                hls_pos=hls2_pos = (int)(strlen(txt_line+i) - strlen(ptr_2hls)) + i;
  457.                              else
  458.                                hls_pos = hls1_pos;
  459.                              hls_start = TRUE;
  460.                            }
  461.                           if (*(txt_line + i))
  462.                             fputc(*(txt_line+i), fp);
  463.                           else
  464.                             break;
  465.                         }
  466.                    }
  467.                   else
  468.                     /*
  469.                        Otherwise, print actual char in string
  470.                     */
  471.                     fputc(*(txt_line+i), fp);
  472.                   j++;
  473.                   i++;
  474.                 }
  475.                S_NEWLINE(fp);
  476.              }
  477. #  if USE_PAGER
  478.             if (pager_flag)
  479.              {
  480.                /*
  481.                   Must we prompt the user?
  482.                */
  483.                if (!tty_am)
  484.                  j = 0;
  485.                else
  486.                 {
  487.                   k = ((nl_found) ? j : i) - nl - hls_chars;
  488.                   j = k / tty_cols;
  489.                   if (   j
  490.                       && tty_xn
  491.                       && !(k % tty_cols))
  492.                     j--;
  493.                 }
  494.                if (lines_printed+j >= tty_rows-1)
  495.                 {
  496.                   if (print_hls)
  497. #    if defined(GCAL_TCAP) && USE_HLS
  498.                     tputs((char *)ehls1s.seq, 1, outchar);
  499. #    else /* !GCAL_TCAP || !USE_HLS */
  500.                     fputs(ehls1s.seq, fp);
  501. #    endif /* !GCAL_TCAP || !USE_HLS */
  502. #    if USE_GER
  503.                   fprintf(fp, "Weiter mit <Return> , <"PAGER_QUIT"> zum Beenden...");
  504. #    else /* !USE_GER */
  505.                   fprintf(fp, "<Return> for more , <"PAGER_QUIT"> to quit...");
  506. #    endif /* !USE_GER */
  507.                   if (print_hls)
  508. #    if defined(GCAL_TCAP) && USE_HLS
  509.                     tputs((char *)ehls1e.seq, 1, outchar);
  510. #    else /* !GCAL_TCAP || !USE_HLS */
  511.                     fputs(ehls1e.seq, fp);
  512. #    endif /* !GCAL_TCAP || !USE_HLS */
  513.                   k = fgetc(stdin);
  514.                   /*
  515.                      Quit the pager by quit command
  516.                   */
  517.                   if (tolower(k) == (int)*PAGER_QUIT)
  518.                    {
  519.                      /*
  520.                         In case leading "quit" char and other text is in stdin buffer:
  521.                           clean whole buffer
  522.                      */
  523.                      while (   ((k=fgetc(stdin)) != '\n')
  524.                             && (k != EOF))
  525.                        ;   /* Void */
  526.                      k = EOF;
  527.                    }
  528.                   else
  529.                     /*
  530.                        In case "quit" char is not leading (anywhere) in stdin buffer:
  531.                          clean buffer while "quit" char not found
  532.                     */
  533.                     if (k != '\n')
  534.                       while (   ((k=fgetc(stdin)) != '\n')
  535.                              && (tolower(k) != (int)*PAGER_QUIT)
  536.                              && (k != EOF))
  537.                         ;   /* Void */
  538.                   /*
  539.                      In case "quit" char is found in stdin buffer now:
  540.                        clean rest of buffer
  541.                   */
  542.                   if (tolower(k) == (int)*PAGER_QUIT)
  543.                    {
  544.                      while (   ((k=fgetc(stdin)) != '\n')
  545.                             && (k != EOF))
  546.                        ;   /* Void */
  547.                      k = EOF;
  548.                    }
  549.                   /*
  550.                      Exit program
  551.                   */
  552.                   if (k == EOF)
  553.                     exit(0);
  554.                   /*
  555.                      Begin scrolling of next page
  556.                   */
  557.                   lines_printed = 0;
  558.                 }
  559.                else
  560.                  lines_printed += (j + 1);
  561.                if (!*(txt_line + i))
  562.                  break;
  563.              }
  564.             else
  565. #  endif /* USE_PAGER */
  566.               if (!*(txt_line + i))
  567.                 break;
  568.           }
  569.        }
  570.       else
  571. #endif /* USE_PAGER || (GCAL_TCAP && USE_HLS) */
  572.        {
  573.          /*
  574.             If mailing option is selected, print output to temporary file
  575.          */
  576.          if (   (tfp != (FILE *)NULL)
  577.              && (fp != (FILE *)stderr))
  578.            fprintf(tfp, "%s\n", txt_line);
  579.          else
  580.            fprintf(fp, "%s\n", txt_line);
  581.        }
  582.     }
  583.    *txt_line = '\0';
  584. }
  585.  
  586.  
  587.  
  588. #ifdef ANSI_PROTO
  589. PUBLIC void
  590. get_tty_hls (const char *sequence_str)
  591. #else /* !ANSI_PROTO */
  592.    PUBLIC void
  593. get_tty_hls (sequence_str)
  594.    const char *sequence_str;
  595. #endif /* !ANSI_PROTO */
  596. /*
  597.    Reads the colours/highlighting sequences from Termcap and assigns them
  598.      to the according variables. if Termcap isn't present, defaults are used.
  599. */
  600. {
  601. #if USE_HLS
  602.    auto       char  *ptr_env=getenv(ENV_VAR_GCALANSI);
  603. #  if defined(GCAL_TCAP)
  604.    auto const char  *ptr_char;
  605. #  endif
  606. #endif
  607.    auto       Bool   hls1_set=FALSE;
  608.    auto       Bool   hls2_set=FALSE;
  609.  
  610.  
  611.    /*
  612.       Check whether highlighting must be disabled (-H<no> given in command line)
  613.    */
  614.    if (!highlight_flag)
  615.     {
  616.       emu_hls = TRUE;
  617.       ehls1s.seq = NO_HLS;
  618.       ehls1e.seq = NO_HLS;
  619.       ehls2s.seq = NO_HLS;
  620.       ehls2e.seq = NO_HLS;
  621.     }
  622.    else
  623.     {
  624.       /*
  625.          If output is not directed to a tty, emulate highlighting sequences
  626.            by marking characters
  627.       */
  628.       if (   !is_tty
  629.           && !emu_hls
  630.           && highlight_flag)
  631.         emu_hls = TRUE;
  632.       /*
  633.          Check whether user defined highlighting sequences are given
  634.            in command line (-H<def>)
  635.       */
  636.       if (sequence_str != (char *)NULL)
  637.         get_hl_seq (sequence_str, &hls1_set, &hls2_set);
  638.       /*
  639.          No or partitial highlighting sequences are given in command line
  640.            -> complete them
  641.       */
  642.       if (   !hls1_set
  643.           || !hls2_set)
  644.        {
  645. #if USE_HLS
  646. #  ifdef GCAL_TCAP
  647.          if (!emu_hls)
  648.           {
  649.             /*
  650.                Try to open termcap file
  651.             */
  652.             tc_no_error = open_termcap ();
  653.             if (tc_no_error)
  654.               get_termcap_hls (&hls1_set, &hls2_set);
  655.             if (ptr_env != (char *)NULL)
  656.              {
  657.                /*
  658.                   Some or all Termcap highlighting sequences are missing:
  659.                     --> use according default ANSI highlighting sequences
  660.                         if environment variable GCALANSI is set
  661.                */
  662.                if (!hls1_set)
  663.                 {
  664.                   ehls1s.seq = HLS1S;
  665.                   ehls1e.seq = HLS1E;
  666.                 }
  667.                if (!hls2_set)
  668.                 {
  669.                   ehls2s.seq = HLS2S;
  670.                   ehls2e.seq = HLS2E;
  671.                 }
  672.              }
  673.             else
  674.               if (   !hls1_set
  675.                   || !hls2_set)
  676.                {
  677.                  /*
  678.                     Some or all Termcap highlighting sequences are missing:
  679.                       --> emulate ALL highlighting sequences by marking character
  680.                           pairs if environment variable GCALANSI is not set
  681.                  */
  682.                  emu_hls = TRUE;
  683.                  ehls1s.seq = BUF_HLS1S;
  684.                  ehls1e.seq = BUF_HLS1E;
  685.                  ehls2s.seq = BUF_HLS2S;
  686.                  ehls2e.seq = BUF_HLS2E;
  687.                }
  688.           }
  689.          else
  690. #  endif /* GCAL_TCAP */
  691.           {
  692.             if (emu_hls)
  693.              {
  694.                /*
  695.                   Use emulation of highlighting sequences
  696.                     in case output is not directed to a tty and the highlighting
  697.                     sequences are not explicit disabled in command line by -H<no>
  698.                */
  699.                if (!hls1_set)
  700.                 {
  701.                   ehls1s.seq = BUF_HLS1S;
  702.                   ehls1e.seq = BUF_HLS1E;
  703.                 }
  704.                if (!hls2_set)
  705.                 {
  706.                   ehls2s.seq = BUF_HLS2S;
  707.                   ehls2e.seq = BUF_HLS2E;
  708.                 }
  709.              }
  710.             else
  711.              {
  712.                /*
  713.                   Use highlighting sequences directly in all other cases
  714.                */
  715.                if (ptr_env != (char *)NULL)
  716.                 {
  717.                   /*
  718.                      If environment variable GCALANSI is set:
  719.                        --> use according default ANSI highlighting sequences
  720.                   */
  721.                   if (!hls1_set)
  722.                    {
  723.                      ehls1s.seq = HLS1S;
  724.                      ehls1e.seq = HLS1E;
  725.                    }
  726.                   if (!hls2_set)
  727.                    {
  728.                      ehls2s.seq = HLS2S;
  729.                      ehls2e.seq = HLS2E;
  730.                    }
  731.                 }
  732.                else
  733.                  if (   !hls1_set
  734.                      || !hls2_set)
  735.                   {
  736.                     /*
  737.                        If environment variable GCALANSI is not set:
  738.                          --> emulate ALL highlighting sequences by marking character pairs
  739.                     */
  740.                     emu_hls = TRUE;
  741.                     ehls1s.seq = BUF_HLS1S;
  742.                     ehls1e.seq = BUF_HLS1E;
  743.                     ehls2s.seq = BUF_HLS2S;
  744.                     ehls2e.seq = BUF_HLS2E;
  745.                   }
  746.              }
  747.           }
  748. #else /* !USE_HLS */
  749.          /*
  750.             Use default highlighting sequences
  751.          */
  752.          if (!hls1_set)
  753.           {
  754.             ehls1s.seq = HLS1S;
  755.             ehls1e.seq = HLS1E;
  756.           }
  757.          if (!hls2_set)
  758.           {
  759.             ehls2s.seq = HLS2S;
  760.             ehls2e.seq = HLS2E;
  761.           }
  762. #endif /* !USE_HLS */
  763.        }
  764.     }
  765.    /*
  766.       Detect and store length of highlighting sequences
  767.    */
  768. #if defined(GCAL_TCAP) && USE_HLS
  769.    /*
  770.       Skip leading padding information for detection of real sequence length
  771.    */
  772.    ptr_char = ehls1s.seq;
  773.    while (isdigit(*ptr_char))
  774.      ptr_char++;
  775.    ehls1s.len = (int)strlen(ptr_char);
  776.    ptr_char = ehls1e.seq;
  777.    while (isdigit(*ptr_char))
  778.      ptr_char++;
  779.    ehls1e.len = (int)strlen(ptr_char);
  780.    ptr_char = ehls2s.seq;
  781.    while (isdigit(*ptr_char))
  782.      ptr_char++;
  783.    ehls2s.len = (int)strlen(ptr_char);
  784.    ptr_char = ehls2e.seq;
  785.    while (isdigit(*ptr_char))
  786.      ptr_char++;
  787.    ehls2e.len = (int)strlen(ptr_char);
  788. #else /* !GCAL_TCAP || !USE_HLS */
  789.    ehls1s.len = (int)strlen(ehls1s.seq);
  790.    ehls1e.len = (int)strlen(ehls1e.seq);
  791.    ehls2s.len = (int)strlen(ehls2s.seq);
  792.    ehls2e.len = (int)strlen(ehls2e.seq);
  793. #endif /* !GCAL_TCAP || !USE_HLS */
  794. }
  795.  
  796.  
  797.  
  798. #if USE_PAGER
  799. #  ifdef ANSI_PROTO
  800. PUBLIC void
  801. get_tty_scr_size (int *rows,
  802.                   int *cols)
  803. #  else /* !ANSI_PROTO */
  804.    PUBLIC void
  805. get_tty_scr_size (rows, cols)
  806.    int *rows;
  807.    int *cols;
  808. #  endif /* !ANSI_PROTO */
  809. /*
  810.    Detects the number of rows and columns of a tty
  811.      and stores the values found in `rows' and `cols'
  812. */
  813. {
  814. #  if !defined(AMIGA) || defined(__GNUC__)
  815.    register int    li=0;
  816.    register int    co=0;
  817.    auto     char  *ptr_env;
  818.  
  819.  
  820.    /*
  821.       First, look into the environment variable pair `LINES' and `COLUMNS'
  822.       resp., `LI' and `CO' in case these are defined and have valid settings:
  823.         use these settings
  824.    */
  825.    ptr_env = getenv(ENV_VAR_LI);
  826.    if (ptr_env != (char *)NULL)
  827.      if (*ptr_env)
  828.       {
  829.         li = my_atoi (ptr_env);
  830.         ptr_env = getenv(ENV_VAR_CO);
  831.         if (ptr_env != (char *)NULL)
  832.           if (*ptr_env)
  833.             co = my_atoi (ptr_env);
  834.       }
  835.    if (   (li > 0)
  836.        && (co > 0))
  837.     {
  838.       *rows = li;
  839.       *cols = co;
  840.     }
  841.    else
  842.     {
  843.       ptr_env = getenv(ENV_VAR_LI2);
  844.       if (ptr_env != (char *)NULL)
  845.         if (*ptr_env)
  846.          {
  847.            li = my_atoi (ptr_env);
  848.            ptr_env = getenv(ENV_VAR_CO2);
  849.            if (ptr_env != (char *)NULL)
  850.              if (*ptr_env)
  851.                co = my_atoi (ptr_env);
  852.          }
  853.       if (   (li > 0)
  854.           && (co > 0))
  855.        {
  856.          *rows = li;
  857.          *cols = co;
  858.        }
  859.       else
  860.        {
  861. #    if defined(OS2) && defined(__GNUC__)
  862.          auto int  info[2];
  863. #    endif /* OS2 && __GNUC__ */
  864. #    if defined(UNIX) && !defined(DJG)
  865. #      ifdef TIOCGWINSZ
  866.          auto struct winsize  wsz;
  867. #      else /* !TIOCGWINSZ */
  868. #        ifdef WIOCGETD
  869.          auto struct uwdata   wsz;
  870. #        endif
  871. #      endif /* !TIOCGWINSZ */
  872. #    endif /* UNIX && !DJG */
  873.  
  874.  
  875. #    if !defined(DJG) && !defined(MSDOS) && !defined(OS2) && !defined(UNIX)
  876.          /*
  877.             For these machines:
  878.               --> defaults only
  879.          */
  880.          *rows = SCREEN_ROWS;
  881.          *cols = SCREEN_COLS;
  882. #    else /* DJG || MSDOS || OS2 || UNIX */
  883. #      ifdef DJG
  884.          /*
  885.             Get the actual number of lines and columns of the video
  886.               by calling the DJGPP-GCC ScreenRows() and ScreenCols() functions.
  887.          */
  888.          *rows = ScreenRows();
  889.          *cols = ScreenCols();
  890. #      elif defined(MSDOS)
  891.          /*
  892.             Look directly into the pc-bios and get the actual number
  893.               of lines and columns of the video
  894.          */
  895.          *rows = peek_byte (0x40, 0x84) + 1;
  896.          /*
  897.             Get lower part of 2-byte word
  898.          */
  899.          *cols = peek_byte (0x40, 0x4b);
  900.          *cols <<= (Ulint)0x08;
  901.          /*
  902.             Add higher part of 2-byte word
  903.          */
  904.          *cols += peek_byte (0x40, 0x4a);
  905. #      elif defined(OS2) && defined(__GNUC__)
  906.          /*
  907.             Get the actual number of lines and columns of the
  908.               video by calling the EMX-GCC _scrsize() function.
  909.          */
  910.          _scrsize(info);
  911.          *cols = s[0];
  912.          *rows = s[1];
  913. #      elif defined(UNIX)
  914.          /*
  915.             Get the actual number of lines and columns of the
  916.               video by calling the ioctl() function.
  917.          */
  918. #        ifdef TIOCGWINSZ
  919.          if (   !ioctl(1, TIOCGWINSZ, &wsz)
  920.              && (wsz.ws_row > 0))
  921.           {
  922.             *rows = wsz.ws_row;
  923.             if (   !ioctl(1, TIOCGWINSZ, &wsz)
  924.                 && (wsz.ws_col > 0))
  925.               *cols = wsz.ws_col;
  926.             else
  927.               *rows = -1;
  928.           }
  929. #        else /* !TIOCGWINSZ */
  930. #          ifdef WIOCGETD
  931.          if (   !ioctl(1, WIOCGETD, &wsz)
  932.              && (wsz.uw_height > 0))
  933.           {
  934.             *rows = wsz.uw_height / wsz.uw_vs;
  935.             if (   !ioctl(1, WIOCGETD, &wsz)
  936.                 && (wsz.uw_width > 0))
  937.               *cols = wsz.uw_width / wsz.uw_hs;
  938.             else
  939.               *rows = -1;
  940.           }
  941. #          endif
  942. #        endif /* !TIOCGWINSZ */
  943. #      endif /* UNIX */
  944.          if (   (*rows == -1)
  945.              && (*cols == -1))
  946.           {
  947. #      if HAVE_LIBTERMCAP || HAVE_LIBTERMLIB
  948.             /*
  949.                If previous actions failed, try to open termcap file
  950.             */
  951.             tc_no_error = open_termcap ();
  952.             if (tc_no_error)
  953.              {
  954.                if (!get_termcap_scr_attrib (rows, cols))
  955.                 {
  956.                   /*
  957.                      No valid Termcap entries:
  958.                        --> defaults only
  959.                   */
  960.                   *rows = SCREEN_ROWS;
  961.                   *cols = SCREEN_COLS;
  962.                 }
  963.              }
  964.             else
  965.              {
  966.                /*
  967.                   Access to termcap file has failed:
  968.                     --> defaults only
  969.                */
  970.                *rows = SCREEN_ROWS;
  971.                *cols = SCREEN_COLS;
  972.              }
  973. #      else /* !HAVE_LIBTERMCAP && !HAVE_LIBTERMLIB */
  974.             /*
  975.                No termcap file available:
  976.                  --> defaults only
  977.             */
  978.             *rows = SCREEN_ROWS;
  979.             *cols = SCREEN_COLS;
  980. #      endif /* !HAVE_LIBTERMCAP && !HAVE_LIBTERMLIB */
  981.           }
  982. #    endif /* DJG || MSDOS || OS2 || UNIX */
  983.        }
  984.     }
  985. #  else /* AMIGA && !__GNUC__ */
  986. #    ifdef AMIGA
  987.    /*
  988.       Amiga gets window size by asking the console.device
  989.    */
  990.    {
  991.      auto long  len;
  992.      auto char  buf[30];
  993.  
  994.  
  995.      Write(Output(), "\2330 q", 4);
  996.      len = Read(Input(), buf, 29);
  997.      buf[len] = '\000';
  998.      sscanf(&buf[5], "%d;%d", rows, cols);
  999.    }
  1000. #    else /* !AMIGA */
  1001.    /*
  1002.       All other systems:
  1003.         --> defaults only
  1004.    */
  1005.    *rows = SCREEN_ROWS;
  1006.    *cols = SCREEN_COLS;
  1007. #    endif /* !AMIGA */
  1008. #  endif /* AMIGA && !__GNUC__ */
  1009.    if (*rows > 1)
  1010.      (*rows)--;
  1011. }
  1012. #endif /* USE_PAGER */
  1013.  
  1014.  
  1015.  
  1016. #if USE_PAGER || USE_HLS
  1017. #  ifdef GCAL_TCAP
  1018. #    ifdef ANSI_PROTO
  1019. LOCAL Bool
  1020. open_termcap (void)
  1021. #    else /* !ANSI_PROTO */
  1022.    LOCAL Bool
  1023. open_termcap ()
  1024. #    endif /* !ANSI_PROTO */
  1025. /*
  1026.    Tries to open the Termcap library and returns the terminal entry found
  1027.      in the module global vector `tc_buf[4096]'.  I cannot rely that we
  1028.      use the access functions of the GNU Termcap library; which allow to pass
  1029.      a NULL pointer to `tgetent()', so this function can check itself, how
  1030.      large `tc_buf[]' must be and allocates it automatically; so i set
  1031.      `tc_buf' to a size of 4096 bytes hoping, that this will be enough
  1032.      for save program operation...
  1033.      may be called only once.
  1034.      returns FALSE if an error has occurred, otherwise TRUE.
  1035. */
  1036. {
  1037. #    if defined(OS2) && defined(__GNUC__)
  1038.    auto   char  *ptr_env=getenv(ENV_VAR_TCAP);
  1039.    auto   char  *ptr_tc;
  1040. #    endif /* OS2 && __GNUC__ */
  1041.    auto   char  *term=getenv(ENV_VAR_TERM);
  1042.    static Bool   tc_accessed=FALSE;
  1043.    auto   Bool   is_error=FALSE;
  1044.  
  1045.  
  1046.    if (!tc_accessed)
  1047.     {
  1048. #    if defined(OS2) && defined(__GNUC__)
  1049.       /*
  1050.          Under OS/2 with GNU-C, we use the default terminal type (ANSI)
  1051.            and access Termcap library instead of printing an informational
  1052.            message and using burned-in defaults if $TERM environment
  1053.            variable isn't set.
  1054.       */
  1055.       if (   term == (char *)NULL
  1056.           || !*term)
  1057.         term = DFLT_TERM;
  1058. #    else /* !OS2 || !__GNUC__ */
  1059.       if (term == (char *)NULL)
  1060.        {
  1061. #      if USE_GER
  1062.          if (warning_level >= 0)
  1063.            fputs("\nUmgebungsvariable $"ENV_VAR_TERM" nicht vorhanden", stderr);
  1064. #      else /* !USE_GER */
  1065.          if (warning_level >= 0)
  1066.            fputs("\nEnvironment variable $"ENV_VAR_TERM" not found", stderr);
  1067. #      endif /* !USE_GER */
  1068.          is_error = TRUE;
  1069.        }
  1070.       else
  1071.         if (!*term)
  1072.          {
  1073. #      if USE_GER
  1074.            if (warning_level >= 0)
  1075.              fputs("\nUmgebungsvariable $"ENV_VAR_TERM" nicht gesetzt", stderr);
  1076. #      else /* !USE_GER */
  1077.            if (warning_level >= 0)
  1078.              fputs("\nEnvironment variable $"ENV_VAR_TERM" not set", stderr);
  1079. #      endif /* !USE_GER */
  1080.            is_error = TRUE;
  1081.          }
  1082.         else
  1083. #    endif /* !OS2 || !__GNUC__ */
  1084.          {
  1085. #    if defined(OS2) && defined(__GNUC__)
  1086.            /*
  1087.               Make sure the Termcap database is available,
  1088.                 i.e. store its access path in environment
  1089.                 explicitly so we are able to refer to it.
  1090.            */
  1091.            if (   ptr_env == NULL
  1092.                || !*ptr_env)
  1093.             {
  1094.               ptr_env = (char *)my_malloc (256,
  1095.                                            124, __FILE__, __LINE__ -1,
  1096.                                            "ptr_env", 0);
  1097.               _searchenv(FNAME_TCAP, "INIT", ptr_env);
  1098.               if (!*ptr_env)
  1099.                 _searchenv(FNAME_TCAP, ENV_VAR_PATH, ptr_env);
  1100.               if (!*ptr_env)
  1101.                 _searchenv(FNAME_TCAP, ENV_VAR_DPATH, ptr_env);
  1102.               if (*ptr_env)
  1103.                {
  1104.                  ptr_tc = (char *)my_malloc (strlen(ptr_env)+9,
  1105.                                              124, __FILE__, __LINE__ -1,
  1106.                                              "ptr_tc", 0);
  1107.                  sprintf(ptr_tc, ENV_VAR_TCAP"=%s", ptr_env);
  1108.                  putenv(ptr_tc);
  1109.                }
  1110.               free(ptr_env);
  1111.             }
  1112. #    endif /* OS2 && __GNUC__ */
  1113.            switch (tgetent(tc_buf, term))
  1114.             {
  1115.               case -1:
  1116. #    if USE_GER
  1117.                 if (warning_level >= 0)
  1118.                   fputs("\n`termcap' Datei wurde nicht vorgefunden", stderr);
  1119. #    else /* !USE_GER */
  1120.                 if (warning_level >= 0)
  1121.                   fputs("\n`termcap' file not found", stderr);
  1122. #    endif /* !USE_GER */
  1123.                 is_error = TRUE;
  1124.                 break;
  1125.               case 0:
  1126. #    if USE_GER
  1127.                 if (warning_level >= 0)
  1128.                   fputs("\nUnbekannter Terminaltyp in $"ENV_VAR_TERM" eingetragen", stderr);
  1129. #    else /* !USE_GER */
  1130.                 if (warning_level >= 0)
  1131.                   fputs("\nUnknown terminal type defined in $"ENV_VAR_TERM, stderr);
  1132. #    endif /* !USE_GER */
  1133.                 is_error = TRUE;
  1134.                 break;
  1135.               default:
  1136.                 ;   /* Void, Termcap access ok */
  1137.             }
  1138.          }
  1139.       if (   is_error
  1140.           && (warning_level >= 0))
  1141.         fputs(".\n\n", stderr);
  1142.       tc_accessed = TRUE;
  1143.       return((Bool)!is_error);
  1144.     }
  1145.    else
  1146.      return(tc_no_error);
  1147. }
  1148.  
  1149.  
  1150.  
  1151. #    if USE_HLS
  1152. #      ifdef ANSI_PROTO
  1153. LOCAL void
  1154. get_ospeed (void)
  1155. #      else /* !ANSI_PROTO */
  1156.    LOCAL void
  1157. get_ospeed ()
  1158. #      endif /* !ANSI_PROTO */
  1159. /*
  1160.    Try to detect terminal speed and store its value to
  1161.      Termcap's global `ospeed' variable
  1162. */
  1163. {
  1164. #      if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS
  1165.    auto struct termios  buf;
  1166.  
  1167.  
  1168.    /*
  1169.       Get terminal mode
  1170.    */
  1171.    tcgetattr(1, &buf);
  1172.    /*
  1173.       Get ospeed
  1174.    */
  1175. #        if HAVE_OSPEED
  1176.    switch (cfgetospeed(&buf))
  1177.     {
  1178. #          ifdef B0
  1179.       case B0:
  1180.         ospeed = 0;
  1181.         break;
  1182. #          endif
  1183. #          ifdef B50
  1184.       case B50:
  1185.         ospeed = 1;
  1186.         break;
  1187. #          endif
  1188. #          ifdef B75
  1189.       case B75:
  1190.         ospeed = 2;
  1191.         break;
  1192. #          endif
  1193. #          ifdef B110
  1194.       case B110:
  1195.         ospeed = 3;
  1196.         break;
  1197. #          endif
  1198. #          ifdef B134
  1199.       case B134:
  1200.         ospeed = 4;
  1201.         break;
  1202. #          endif
  1203. #          ifdef B150
  1204.       case B150:
  1205.         ospeed = 5;
  1206.         break;
  1207. #          endif
  1208. #          ifdef B200
  1209.       case B200:
  1210.         ospeed = 6;
  1211.         break;
  1212. #          endif
  1213. #          ifdef B300
  1214.       case B300:
  1215.         ospeed = 7;
  1216.         break;
  1217. #          endif
  1218. #          ifdef B600
  1219.       case B600:
  1220.         ospeed = 8;
  1221.         break;
  1222. #          endif
  1223. #          ifdef B1200
  1224.       case B1200:
  1225.         ospeed = 9;
  1226.         break;
  1227. #          endif
  1228. #          ifdef B1800
  1229.       case B1800:
  1230.         ospeed = 10;
  1231.         break;
  1232. #          endif
  1233. #          ifdef B2400
  1234.       case B2400:
  1235.         ospeed = 11;
  1236.         break;
  1237. #          endif
  1238. #          ifdef B4800
  1239.       case B4800:
  1240.         ospeed = 12;
  1241.         break;
  1242. #          endif
  1243. #          ifdef B9600
  1244.       case B9600:
  1245.         ospeed = 13;
  1246.         break;
  1247. #          endif
  1248. #          ifdef EXTA
  1249.       case EXTA:
  1250.         ospeed = 14;
  1251.         break;
  1252. #          endif
  1253. #          ifdef EXTB
  1254.       case EXTB:
  1255.         ospeed = 15;
  1256.         break;
  1257. #          endif
  1258. #          ifdef B57600
  1259.       case B57600:
  1260.         ospeed = 16;
  1261.         break;
  1262. #          endif
  1263. #          ifdef B115200
  1264.       case B115200:
  1265.         ospeed = 17;
  1266.         break;
  1267. #          endif
  1268.       default:
  1269.         ;   /* Void */
  1270.     }
  1271. #        endif /* HAVE_OSPEED */
  1272. #      else /* !HAVE_TERMIOS_H || !HAVE_TERMIOS_FUNC */
  1273. #        if TCGETA
  1274.    auto struct termio  buf;
  1275.  
  1276.  
  1277.    /*
  1278.       Get terminal mode
  1279.    */
  1280.    ioctl(1, TCGETA, &buf);
  1281.    /*
  1282.       Get ospeed
  1283.    */
  1284. #          if HAVE_OSPEED
  1285.    ospeed = buf.c_cflag & CBAUD;
  1286. #          endif
  1287. #        else /* !TCGETA */
  1288.    auto struct sgttyb  buf;
  1289.  
  1290.  
  1291.    /*
  1292.       Get terminal mode
  1293.    */
  1294.    ioctl(1, TIOCGETP, &buf);
  1295.    /*
  1296.       Get ospeed
  1297.    */
  1298. #          if HAVE_OSPEED
  1299.    ospeed = buf.sg_ospeed;
  1300. #          endif
  1301. #        endif /* !TCGETA */
  1302. #      endif /* !HAVE_TERMIOS_H || !HAVE_TERMIOS_FUNC */
  1303. }
  1304.  
  1305.  
  1306.  
  1307. #      ifdef ANSI_PROTO
  1308. LOCAL int
  1309. outchar (int ch)
  1310. #      else /* !ANSI_PROTO */
  1311.    LOCAL void
  1312. outchar (ch)
  1313.    int ch;
  1314. #      endif /* !ANSI_PROTO */
  1315. /*
  1316.    Termcap's `tputs()' prints a character to module local defined
  1317.      file `fp_outchar', which must be assigned before using `tputs()'.
  1318. */
  1319. {
  1320.   return(fputc(ch, fp_outchar));
  1321. }
  1322.  
  1323.  
  1324.  
  1325. #      ifdef ANSI_PROTO
  1326. LOCAL Bool
  1327. get_termcap_hls (Bool *hls1_set,
  1328.                  Bool *hls2_set)
  1329. #      else /* !ANSI_PROTO */
  1330.    LOCAL Bool
  1331. get_termcap_hls (hls1_set, hls2_set)
  1332.    Bool *hls1_set;
  1333.    Bool *hls2_set;
  1334. #      endif /* !ANSI_PROTO */
  1335. /*
  1336.    Inspects the Termcap buffer `tc_buf' to detect the tty colour/highlighting sequences.
  1337.      the module global vector `char tc_buf[]' must be filled previously.
  1338.      may be called only once.
  1339.      returns FALSE if an error has occured, otherwise TRUE.
  1340. */
  1341. {
  1342.    register int    i=(*hls1_set) ? 2 : 0;
  1343.    register int    j=(*hls2_set) ? TC_MC_MAX-2 : TC_MC_MAX;
  1344.    static   char  *tc[TC_MC_MAX]={
  1345.                                    TC_MC_HL1S,
  1346.                                    TC_MC_HL1E,
  1347.                                    TC_MC_HL2S,
  1348.                                    TC_MC_HL2E
  1349.                                  };
  1350. #      if HAVE_OSPEED
  1351.    static   char  *padding;
  1352. #      endif
  1353.    static   char  *area;
  1354.    auto     char  *ptr_char;
  1355.    auto     char  *ptr_area;
  1356.    auto     Bool   is_error=FALSE;
  1357.  
  1358.  
  1359.    area = (char *)my_malloc (strlen(tc_buf),
  1360.                              124, __FILE__, __LINE__ -1,
  1361.                              "area", 0);
  1362.    ptr_area = area;
  1363. #      if HAVE_OSPEED
  1364.    /*
  1365.       Get the padding sequence
  1366.    */
  1367.    padding = tgetstr("pc", &ptr_area);
  1368.    PC = (padding) ? *padding : '\0';
  1369.    /*
  1370.       Get the terminal speed
  1371.    */
  1372.    get_ospeed ();
  1373. #      endif
  1374.    for ( ; (i < j) && !is_error ; i++)
  1375.     {
  1376.       ptr_char = tgetstr(tc[i], &ptr_area);
  1377.       if (ptr_char != (char *)NULL)
  1378.        {
  1379.          switch (i)
  1380.           {
  1381.             case 0:
  1382.               ehls1s.seq = ptr_char;
  1383.               break;
  1384.             case 1:
  1385.               ehls1e.seq = ptr_char;
  1386.               *hls1_set = TRUE;
  1387.               break;
  1388.             case 2:
  1389.               ehls2s.seq = ptr_char;
  1390.               break;
  1391.             case 3:
  1392.               ehls2e.seq = ptr_char;
  1393.               *hls2_set = TRUE;
  1394.               break;
  1395.             default:
  1396.               /*
  1397.                  Error, more then 2 highlight sequence pairs given
  1398.               */
  1399.               is_error = TRUE;
  1400.           }
  1401.        }
  1402.       else
  1403.         /*
  1404.            Error, no terminal capability string found for mode `tc[i]'
  1405.         */
  1406.         is_error = TRUE;
  1407.     }
  1408.  
  1409.    return((Bool)!is_error);
  1410. }
  1411. #    endif /* USE_HLS */
  1412.  
  1413.  
  1414.  
  1415. #    if USE_PAGER
  1416. #      ifdef ANSI_PROTO
  1417. LOCAL Bool
  1418. get_termcap_scr_attrib (int *rows,
  1419.                         int *cols)
  1420. #      else /* !ANSI_PROTO */
  1421.    LOCAL Bool
  1422. get_termcap_scr_attrib (rows, cols)
  1423.    int *rows;
  1424.    int *cols;
  1425. #      endif /* !ANSI_PROTO */
  1426. /*
  1427.    Inspects the Termcap buffer `tc_buf' to detect first the amount of rows
  1428.      and columns of the tty, then whether the terminal wraps the line
  1429.      automatically at right margin. if Termcap isn't present, defaults are used.
  1430.      the module global vector `char tc_buf[]' must be filled previously.
  1431.      may be called only once.
  1432.      returns FALSE if an error has occured, otherwise TRUE.
  1433. */
  1434. {
  1435.    /*
  1436.       Get the amount of tty rows and columns
  1437.    */
  1438.    if (   tgetnum("li") == -1
  1439.        || tgetnum("co") == -1)
  1440.      return(FALSE);
  1441.    else
  1442.     {
  1443.       *rows = tgetnum("li");
  1444.       *cols = tgetnum("co");
  1445.       /*
  1446.          Check whether tty wraps the line automatically
  1447.            at right margin and ignores newline after wrapping.
  1448.       */
  1449.       tty_am = tgetflag("am");
  1450.       tty_xn = tgetflag("xn");
  1451.     }
  1452.  
  1453.    return(TRUE);
  1454. }
  1455. #    endif /* USE_PAGER */
  1456. #  else /* !GCAL_TCAP */
  1457. #    if defined(MSDOS) && USE_PAGER
  1458. #      ifdef ANSI_PROTO
  1459. LOCAL Uchar
  1460. peek_byte (Uint segment,
  1461.            Uint offset)
  1462. #      else /* !ANSI_PROTO */
  1463.    LOCAL Uchar
  1464. peek_byte (segment, offset)
  1465.    Uint segment;
  1466.    Uint offset;
  1467. #      endif /* !ANSI_PROTO */
  1468. /*
  1469.    Gets a byte of ibm/pc-memory from address (segment:offset)
  1470. */
  1471. {
  1472.    auto Ulint       long_tmp;
  1473.    auto Uchar far  *ptr_char;
  1474.  
  1475.  
  1476.    long_tmp = (Ulint)segment;
  1477.    long_tmp <<= (Ulint)0x10;
  1478.    long_tmp += (Ulint)offset;
  1479.    ptr_char = (Uchar far *)long_tmp;
  1480.  
  1481.    return(*ptr_char);
  1482. }
  1483. #    endif /* MSDOS && USE_PAGER */
  1484. #  endif /* !GCAL_TCAP */
  1485. #endif /* USE_PAGER || USE_HLS */
  1486.  
  1487.  
  1488.  
  1489. #ifdef ANSI_PROTO
  1490. LOCAL void
  1491. get_hl_seq (const char *sequence_str,
  1492.                   Bool *hls1_set,
  1493.                   Bool *hls2_set)
  1494. #else /* !ANSI_PROTO */
  1495.    LOCAL void
  1496. get_hl_seq (sequence_str, hls1_set, hls2_set)
  1497.    const char *sequence_str;
  1498.          Bool *hls1_set;
  1499.          Bool *hls2_set;
  1500. #endif /* !ANSI_PROTO */
  1501. /*
  1502.    Highlighting sequences/marking characters are given in command line
  1503.    (-H<seq1_start:seq1_end:seq2_start:seq2_end> option set)
  1504.    i.e.:  the colon separated string `sequence_str', which should contain
  1505.           highlighting sequence/marking character pairs (2 pairs maximum,
  1506.           first for actual day, second for holiday; seq?_start enables,
  1507.           seq?_end disables), is delivered,
  1508.           e.g.:   \x20:\x20:\x1:#
  1509.                     marks holiday date like:  \x1`date'#
  1510.                     using given marking characters.
  1511.           e.g.:   \x1b[34;42m:\x1b[0;40m      or
  1512.                   \033[34;42m:\033[0;40m      or
  1513.                   \E[34;42m:\E[0;40m
  1514.                     thus all defines starting (ANSI)escape highlighting sequence
  1515.                     \x1b[34;42m used for actual day and ending (ANSI)escape
  1516.                     highlighting sequence \x1b[0;40m with no given highlighting
  1517.                     sequence for holiday, so default highlighting sequences
  1518.                     for holiday are used (unnotated entries are always skipped).
  1519.           control code definitions may contain any printable characters.
  1520.           non-printable characters may be encoded in octal or hexadecimal
  1521.           notation. The abbreviation \E resp., \e directly encodes the escape
  1522.           character (\x1B resp., \033).
  1523.           a character can be encoded octal by typing \nnn (BACKSLASH-octal
  1524.           digit(s)), where n must be a valid octal digit (0...7). normally,
  1525.           3 octal digits must be given. if the octal character code consists
  1526.           of 1 or 2 octal digits, leading zeroes must be added; except the case,
  1527.           the encoded octal character is given last in single sequence.
  1528.           a character can be encoded hexadecimal by typing \xnn (BACKSLASH-x-
  1529.           hexadecimal digit(s)), where n must be a valid hexadecimal digit
  1530.           (0...9A...Fa...f). normally, 2 hexadecimal digits must be given. if
  1531.           the hexadecimal character code consists of 1 hexadecimal digit,
  1532.           a leading zero must be added; except the case, the encoded
  1533.           hexadecimal character is given last in single sequence.
  1534.           if the sequence separator character, the colon `:' character
  1535.           itself is used for marking character, it must be specified
  1536.           either octal by \072 or hexadecimal by \x3A.
  1537.    get, convert and store them in the global hls structs.
  1538.    returns TRUE if all actions are successfull, otherwise FALSE.
  1539. */
  1540. {
  1541.    register       int    i=0;
  1542.    register       int    n;
  1543.    register       int    j;
  1544.    register       int    k;
  1545.    register       int    diff;
  1546.    register       int    seq_no=0;
  1547.    static         char  *buf_hls[TC_MC_MAX];
  1548.    auto     const char  *ptr_char=sequence_str;
  1549.    auto           char  *ptr_err=(char *)NULL;
  1550.    auto           char   hc_text[5];
  1551.    auto           Bool   is_error=FALSE;
  1552.    auto           Bool   is_hex;
  1553.    auto           Bool   is_oct;
  1554.    auto           Bool   is_esc;
  1555.  
  1556.  
  1557.    *hls1_set=*hls2_set = FALSE;
  1558.    while (   *ptr_char
  1559.           && !is_error
  1560.           && (seq_no < TC_MC_MAX))
  1561.     {
  1562.       /*
  1563.          Copy highlighting sequence/marking character to temporary
  1564.            sequence string (until column found)
  1565.       */
  1566.       while(   *ptr_char
  1567.             && (*ptr_char != *SEP)
  1568.             && (i < MAXLEN))
  1569.         s[i++] = *ptr_char++;
  1570.       /*
  1571.          Skip if given sequence string is too long...  :(
  1572.       */
  1573.       if (i == MAXLEN)
  1574.         break;
  1575.       if (*ptr_char)
  1576.         ptr_char++;
  1577.       if (i)
  1578.        {
  1579.          s[i] = '\0';
  1580.          i=n = 0;
  1581.          /*
  1582.             Convert all textual:
  1583.               hex character sequences \xnn
  1584.               oct character sequences \nnn
  1585.               esc character sequences \E or \e
  1586.             found in sequence string to real characters
  1587.          */
  1588.          while (s[i+n])
  1589.           {
  1590.             is_hex=is_oct=is_esc = FALSE;
  1591.             diff = 0;
  1592.             if (s[i+n] == '\\')
  1593.              {
  1594.                is_esc = (Bool)(tolower(s[i+n+1]) == 'e');
  1595.                is_hex = (Bool)(tolower(s[i+n+1]) == 'x');
  1596.                is_oct = (Bool)isdigit(s[i+n+1]);
  1597.              }
  1598.             if (is_esc)
  1599.              {
  1600.                s[i] = '\033';   /* \x1b */
  1601.                n++;
  1602.              }
  1603.             else
  1604.               if (   is_hex
  1605.                   || is_oct)
  1606.                {
  1607.                  k = 0;
  1608.                  if (is_hex)
  1609.                   {
  1610.                     hc_text[k++] = '0';
  1611.                     hc_text[k++] = 'x';
  1612.                   }
  1613.                  else
  1614.                   {
  1615.                     if (s[i+n+1] != '0')
  1616.                       hc_text[k++] = '0';
  1617.                     else
  1618.                       diff = 1;
  1619.                     hc_text[k++] = s[i+n+1];
  1620.                   }
  1621.                  /*
  1622.                     Copy hex/oct digits to prefix
  1623.                  */
  1624.                  j = i + n + 2;
  1625.                  while (   s[j]
  1626.                         && (s[j] != *SEP)
  1627.                         && (k < 4-diff))
  1628.                    hc_text[k++] = s[j++];
  1629.                  hc_text[k] = '\0';
  1630.                  /*
  1631.                     Convert textual hex/oct character to decimal value
  1632.                  */
  1633. #if HAVE_STRTOL
  1634.                  j = (int)strtol(hc_text, &ptr_err, 0);
  1635. #else /* !HAVE_STRTOL */
  1636.                  ptr_err = hc_text + 1;
  1637.                  if (is_hex)
  1638.                    ptr_err++;
  1639.                  j = sbyte2int (ptr_err, (is_hex) ? 16 : 8);
  1640. #endif /* !HAVE_STRTOL */
  1641.                  /*
  1642.                     If conversion error occurs (either invalid chars in
  1643.                       hex/oct character sequence or \x0 resp., \000 given)
  1644.                       --> abort
  1645.                  */
  1646.                  if (   !j
  1647. #if HAVE_STRTOL
  1648.                      || *ptr_err
  1649. #endif
  1650.                     )
  1651.                   {
  1652.                     is_error = TRUE;
  1653.                     break;
  1654.                   }
  1655.                  /*
  1656.                     Put converted character code back to sequence string
  1657.                  */
  1658.                  s[i] = (char)j;
  1659.                  n += (k - 2 + diff) + 1;
  1660.                }
  1661.             i++;
  1662.             s[i] = s[i+n];
  1663.           }
  1664.          if (!is_error)
  1665.           {
  1666.             /*
  1667.                Store highlighting sequence/marker character
  1668.                  in according global highlighting sequence
  1669.                  struct_variable using static buffer `buf_hls[]'
  1670.             */
  1671.             n = (int)strlen(s);
  1672.             buf_hls[seq_no] = (char *)my_malloc (n+1,
  1673.                                                  124, __FILE__, __LINE__ -1,
  1674.                                                  "buf_hls", seq_no);
  1675.             strcpy(buf_hls[seq_no], s);
  1676.             switch (seq_no)
  1677.              {
  1678.                case 0:
  1679.                  ehls1s.seq = buf_hls[seq_no];
  1680.                  ehls1s.len = n;
  1681.                  break;
  1682.                case 1:
  1683.                  ehls1e.seq = buf_hls[seq_no];
  1684.                  ehls1e.len = n;
  1685.                  *hls1_set = TRUE;
  1686.                  break;
  1687.                case 2:
  1688.                  ehls2s.seq = buf_hls[seq_no];
  1689.                  ehls2s.len = n;
  1690.                  break;
  1691.                case 3:
  1692.                  ehls2e.seq = buf_hls[seq_no];
  1693.                  ehls2e.len = n;
  1694.                  *hls2_set = TRUE;
  1695.                  break;
  1696.                default:
  1697.                  ;   /* Void */
  1698.              }
  1699.           }
  1700.        }
  1701.       i = 0;
  1702.       seq_no++;
  1703.     }
  1704.    /*
  1705.       Either real highlighting sequences (ESC-char..., lenght > 1) only or
  1706.         marking characters (lenght == 1) only can be managed
  1707.         -> avoid mixture of both...
  1708.    */
  1709. #if USE_HLS
  1710.    if (*hls1_set)
  1711.      if (   (   (ehls1s.len == 1)
  1712.              && (ehls1e.len != 1))
  1713.          || (   (ehls1s.len != 1)
  1714.              && (ehls1e.len == 1)))
  1715.        *hls1_set = FALSE;
  1716.    if (*hls2_set)
  1717.      if (   (   (ehls2s.len == 1)
  1718.              && (ehls2e.len != 1))
  1719.          || (   (ehls2s.len != 1)
  1720.              && (ehls2e.len == 1)))
  1721.        *hls2_set = FALSE;
  1722.    if (*hls1_set)
  1723.     {
  1724.       if (   (ehls1s.len == 1)
  1725.           && (ehls1e.len == 1))
  1726.        {
  1727.          if (*hls2_set)
  1728.           {
  1729.             if (   (ehls2s.len == 1)
  1730.                 && (ehls2e.len == 1))
  1731.               emu_hls = TRUE;
  1732.             else
  1733.              {
  1734.                if (emu_hls)
  1735.                  *hls2_set = FALSE;
  1736.                else
  1737.                  *hls1_set = FALSE;
  1738.              }
  1739.           }
  1740.          else
  1741.            if (!emu_hls)
  1742.              *hls1_set = FALSE;
  1743.        }
  1744.       else
  1745.        {
  1746.          if (*hls2_set)
  1747.           {
  1748.             if (   (ehls2s.len != 1)
  1749.                 && (ehls2e.len != 1))
  1750.               ;  /* Void, ok */
  1751.             else
  1752.              {
  1753.                if (emu_hls)
  1754.                  *hls1_set = FALSE;
  1755.                else
  1756.                  *hls2_set = FALSE;
  1757.              }
  1758.           }
  1759.          else
  1760.            if (emu_hls)
  1761.              *hls1_set = FALSE;
  1762.        }
  1763.     }
  1764.    if (   !*hls1_set
  1765.        && *hls2_set)
  1766.     {
  1767.       if (   (ehls2s.len == 1)
  1768.           && (ehls2e.len == 1))
  1769.        {
  1770.          if (!emu_hls)
  1771.            *hls2_set = FALSE;
  1772.        }
  1773.       else
  1774.         if (emu_hls)
  1775.           *hls2_set = FALSE;
  1776.     }
  1777.    if (   *hls1_set
  1778.        && *hls2_set)
  1779.      if (   emu_hls
  1780.          && (ehls1s.len > 1)
  1781.          && (ehls2s.len > 1))
  1782.        *hls1_set=*hls2_set = FALSE;
  1783. #else /* !USE_HLS */
  1784.    if (*hls1_set)
  1785.      if (   ehls1s.len != 1
  1786.          || ehls1e.len != 1)
  1787.        *hls1_set = FALSE;
  1788.    if (*hls2_set)
  1789.      if (   ehls2s.len != 1
  1790.          || ehls2e.len != 1)
  1791.        *hls2_set = FALSE;
  1792. #endif /* !USE_HLS */
  1793. }
  1794.  
  1795.  
  1796.  
  1797. #if !HAVE_STRTOL
  1798. #  ifdef ANSI_PROTO
  1799. LOCAL int
  1800. sbyte2int (const char *s,
  1801.            const int   base)
  1802. #  else /* !ANSI_PROTO */
  1803.    LOCAL int
  1804. sbyte2int (s, base)
  1805.    const char *s;
  1806.    const int   base;
  1807. #  endif /* !ANSI_PROTO */
  1808. /*
  1809.    Converts a textual b-adic string `s', which contains the absolute
  1810.      textual representation of a byte given in number base `base' (2-16)
  1811.      to decimal base and returns its value converted to int in `res'.
  1812.      If an error occurs, zero is returned.
  1813. */
  1814. {
  1815.   register       int    val;
  1816.   register       int    res=0;
  1817.   register       int    mul=1;
  1818.   register       int    len=(int)strlen(s);
  1819.   register       int    len_base_str;
  1820.   static   const char   base_str[]="0123456789abcdef";
  1821.   auto     const char  *ptr_char=s+(len-1);
  1822.  
  1823.  
  1824.   len_base_str = (int)strlen(base_str);
  1825.   if (   !len
  1826.       || base < 2
  1827.       || base > len_base_str)
  1828.     return(0);
  1829.   for ( ; len ; len--)
  1830.    {
  1831.      if (strchr(base_str, tolower(*ptr_char)) == (char *)NULL)
  1832.        return(0);
  1833.      val = len_base_str - (int)strlen(strchr(base_str, *ptr_char--));
  1834.      if (val > base)
  1835.        return(0);
  1836.      res += (val * mul);
  1837.      mul *= base;
  1838.    }
  1839.  
  1840.   return(res);
  1841. }
  1842. #endif /* !HAVE_STRTOL */
  1843.  
  1844.  
  1845.  
  1846. #if !HAVE_STRSTR
  1847. #  ifdef ANSI_PROTO
  1848. LOCAL char *
  1849. my_strstr (const char *txt,
  1850.            const char *pat)
  1851. #  else /* !ANSI_PROTO */
  1852.    LOCAL char *
  1853. my_strstr (txt, pat)
  1854.    const char *txt;
  1855.    const char *pat;
  1856. #  endif /* !ANSI_PROTO */
  1857. /*
  1858.    Search needle `pat' in haystack `txt'   =8^)
  1859.      (emulates the ANSI C strstr() function; not very well optimized).
  1860. */
  1861. {
  1862.    register       int    i=(int)strlen(txt);
  1863.    register       int    j=(int)strlen(pat);
  1864.    register       int    k;
  1865.    auto     const char  *ptr_char=txt;
  1866.  
  1867.  
  1868.    if (!j)
  1869.      return(ptr_char);
  1870.    if (i < j)
  1871.      return((char *)NULL);
  1872.    for (i=0 ; *ptr_char ; i++,ptr_char++)
  1873.     {
  1874.       for (k=0,j=i ; pat[k] && (txt[j]==pat[k]) ; j++,k++)
  1875.         ;
  1876.       if (   k
  1877.           && !pat[k])
  1878.         return(ptr_char);
  1879.     }
  1880.  
  1881.    return((char *)NULL);
  1882. }
  1883. #endif /* !HAVE_STRSTR */
  1884.